package com.prpat;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

class MessageHandler implements Runnable
{
	private Message message;
	private Socket incoming;
	
	/**
	 * {@link ObjectOutputStream} to write answers to.
	 */
	private ObjectOutputStream out;

	/**
	 * {@link ObjectInputStream} to read {@link Message messages} from.
	 */
	private ObjectInputStream in;
	
	MessageHandler(Socket clientSocket)
	{
		incoming = clientSocket;
	}

	private void handleMessage() 
	{
		switch(message.getType())
		{
			case Message.REQUEST:
				TaskAssistant.display.append("Received request from : " + message.getSource() + "\n");
				handleRequest();
				break;
			case Message.REPLY:
				TaskAssistant.display.append("Received reply from : " + message.getSource() + "\n");
				TaskAssistant.display.append("The result is : " + message.getMessage() + "\n");
				break;
			default:
				break;
		}
		
	}

	private void handleRequest() 
	{
		String name = translator(message.getMessage());
		
		name = "files/" + name + message.getRange();
		
		createFile(name);
		appendToFile(name);
		terminal(new String[] {"john", name});
		String ans = terminal(new String[] {"john", "--show", name});
		Message mes = new Message(ans, message.getRange(), Message.REPLY);
		Thread client = new Thread(new Client(mes));
		client.setName("PRPAT-Client # "+(TaskAssistant.CLIENT_COUNT));
		client.start();
		ans = terminal(new String[] {"rm", "-f", name});
	}
	
	/**
	 * 
	 * @param str the hash received in a message
	 * @return a unique name for the file that will store the hash
	 */
	private String translator(String str) 
	{
		String res = "";
		
		if( countOccurrences(str, "$".charAt(0)) < 3)
			return String.valueOf( 1 + (long)(Math.random() * ( Long.MAX_VALUE ) ) );
		
		String tmp = str.split("\\$")[3];
		tmp = tmp.split("\\:")[0];
		for (char chr : str.toCharArray())
		{
			Integer c = (int)chr;
			res += c.toString();
		}
		return res.length() > 100 ? res.substring(0, 100) : res;
	}
	
	/**
	 * 
	 * @param haystack String that is being checked
	 * @param needle char that is being counted in <b>haystack</b>
	 * @return the number of occurrences of <b>needle</b> in a <b>haystack</b>
	 */
	private int countOccurrences(String haystack, char needle)
	{
	    int count = 0;
	    for (int i=0; i < haystack.length(); i++)
	    	if (haystack.charAt(i) == needle)
	        	count++;

	    return count;
	}

	private void appendToFile(String name) 
	{
		try 
		{
			FileWriter fstream = new FileWriter(name, true);
			BufferedWriter out = new BufferedWriter(fstream);
			out.write(message.getMessage());
			//Close the output stream
			out.close();
		} 
		catch (IOException e) 
		{
			System.err.println(this.getClass().getName() + ", appendToFile, e");
		}
		
	}

	private void createFile(String name)
	{
		File f;
		f = new File(name);
		boolean exists = f.exists();
		if(exists)
		{
			terminal(new String[]{"rm", "-f", name});
			exists = f.exists();
		}
		if(!exists)
		{
			try
			{
				f.createNewFile();
			}
			catch (IOException e) 
			{
				System.err.println(this.getClass().getName() + ", createFile, e");
			}
		}
	}

	private String terminal(String[] args)
	{
		String output = "";
		try 
        {
			Process child = Runtime.getRuntime().exec(args);
			
			// Get the input stream and read from it the command output
			InputStream in = child.getInputStream();
			int c;
			
			while ((c = in.read()) != -1) 
				output = output + (char)c;
			
			in.close();
        }
        catch (IOException e) 
        {
        	System.err.println("MessageHandler, terminal, " + e.getMessage());
        }
		TaskAssistant.display.append(output+"\n");
		return output;
	}
	
	
	/**
	 * 
	 */
	public void run() 
	{
		try 
		{
			out = new ObjectOutputStream(incoming.getOutputStream());
			in = new ObjectInputStream(incoming.getInputStream());
			
			message = (Message) in.readObject();
			
			handleMessage();
		} 
		catch (IOException e) 
		{
			try 
			{
				out.close();
			} 
			catch (IOException e1) 
			{
				System.err.println("Message handler, run(), IOException " + e1.getMessage());
			}
			System.err.println("Message handler, run(), IOException " + e.getMessage());
		} 
		catch (ClassNotFoundException e) 
		{
			System.err.println("Message handler, run(),ClassNotFoundException " + e.getMessage());
		}
	}

}
